// 辅助函数

#include <iostream>
#include <string>
using namespace std;
using std::cin;
using std::cout;
using std::string;

long get_a_target_long()
{
long target = 0;
    cout << "target (0~" << RAND_MAX << "): ";
    cin >> target;
    return target;
}

string get_a_target_string()
{
long target = 0;
char buf[10];

    cout << "target (0~" << RAND_MAX << "): ";
    cin >> target;
    snprintf(buf, 10, "%ld", target);
    return string(buf);
}

int compareLongs(const void* a, const void* b)
{
    return ( *(long*)a - *(long*)b );
}

int compareStrings(const void* a, const void* b)
{
    if( *(string*)a > *(string*)b )
        return 1;
    else if( *(string*)a < *(string*)b )
        return -1;
    else
        return 0;
}




// 使用容器array

#include <array>
#include <iostream>
#include <ctime>
#include <cstdlib> // qsort, bsearch, NULL

#define ASIZE 500000

namespace jj01
{
void test_array()
{
    cout << "\ntest_array().......... \n";

array<long, ASIZE> c;

clock_t timeStart = clock();
    for(long i=0; i< ASIZE; ++i) {
        c[i] = rand();
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "array.size()= " << c.size() << endl;
    //cout << "array.max_size()= " << c.max_size() << endl;
    cout << "array.front()= " << c.front() << endl;
    cout << "array.back()= " << c.back() << endl;
    cout << "array.data()= " << c.data() << endl;

long target = get_a_target_long();

    timeStart = clock();
    qsort(c.data(), ASIZE, sizeof(long), compareLongs);
long* pItem = (long*)bsearch(&target, c.data(), ASIZE, sizeof(long), compareLongs);
    cout << "qsort()+bsearch(), milli-seconds: " << (clock() - timeStart) << endl;  //
    if(pItem != NULL)
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
} // test_array()
} // namespace jj01i




// 使用容器vector

#include <vector>
#include <stdexcept>
#include <string>
#include <cstdlib>  // abort()
#include <cstdio>   // snprintf()
#include <iostream>
#include <algorithm>    // sort()

namespace jj02
{
void test_vector(long& value)
{
    cout << "\ntest_vector().......... \n";

vector<string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push_back(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
                // 曾经最高 i=? then std::bad_alloc
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "vector.size()= " << c.size() << endl;
    //cout << "vector.max_size()= " << c.max_size() << endl;
    cout << "vector.front()= " << c.front() << endl;
    cout << "vector.back()= " << c.back() << endl;
    cout << "vector.data()= " << c.data() << endl;
    cout << "vector.capacity()= " << c.capacity() << endl;

string target = get_a_target_string();
    {
    timeStart = clock();
auto pItem = ::find(c.begin(), c.end(), target);
    cout << "::find(), milli-seconds : " << (clock() - timeStart) << endl;

    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
    }

    {
    timeStart = clock();
    sort(c.begin(), c.end());
string* pItem = (string*)bsearch(&target, c.data(), 
                                c.size(), sizeof(string), compareStrings);
    cout << "sort()+bsearch(), milli-seconds : " << (clock() - timeStart) << endl;

    if(pItem != NULL)
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
    }
} // test_vector()
} // namespace jj02




// 使用容器list

#include <list>

namespace jj03
{
void test_list(long& value)
{
    cout << "test_list().......... \n";

list<string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try
        {
            snprintf(buf, 10, "%d", rand());
            c.push_back(string(buf));
        }
        catch(const std::exception& e)
        {
            std::cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "list.size()= " << c.size() << endl;
    cout << "list.max_size()= " << c.max_size() << endl;
    cout << "list.front()= " << c.front() << endl;
    cout << "list.back()= " << c.back() << endl;

string target = get_a_target_string();
    timeStart = clock();
auto pItem = ::find(c.begin(), c.end(), target);
    cout << "::find(), milli-seconds : " << (clock() - timeStart) << endl;

    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;

    timeStart = clock();
    c.sort();
    cout << "sort(), milli-seconds : " << (clock() - timeStart) << endl;
} // test_list()
} // namespace jj03



// 使用容器forward_list

#include <forward_list>

namespace jj04
{
void test_forward_list(long& value)
{
    cout << "test_forward_list().......... \n";

forward_list<string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push_front(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl; //
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "forward_list.max_size()= " << c.max_size() << endl;
    cout << "forward_list.front()= " << c.front() << endl;
    //cout << "forward_list.back()= " << c.back() << endl; // 没有成员back()
    //cout << "forward_list.size()= " << c.size() << endl; // 没有成员size()

string target = get_a_target_string();
    timeStart = clock();
auto pItem = ::find(c.begin(), c.end(), target);
    cout << "::find(), milli-seconds : " << (clock() - timeStart) << endl; //

    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;

    timeStart = clock();
    c.sort();
    cout << "sort(), milli-seconds : " << (clock() - timeStart) << endl; //
} // test_forward_list()
} // namespace jj04




// 使用容器deque

#include <deque>

namespace jj05
{
void test_deque(long& value)
{
    cout << "\ntest_deque().......... \n";

deque<string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push_back(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "deque.size()= " << c.size() << endl;
    cout << "deque.front()= " << c.front() << endl;
    cout << "deque.back()= " << c.back() << endl;
    cout << "deque.max_size()= " << c.max_size() << endl;

string target = get_a_target_string();
    timeStart = clock();
auto pItem = ::find(c.begin(), c.end(), target);
    cout << "::find(), milli-seconds : " << (clock() - timeStart) << endl; //

    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;

    timeStart = clock();
    ::sort(c.begin(), c.end());
    cout << "::sort(), milli-seconds : " << (clock() - timeStart) << endl; //
} // test_deque()
} // namespace jj05




// 使用容器Stack

#include <stack>

namespace jj06
{
void test_stack(long& value)
{
    cout << "test_stack()..........\n";

stack<string> c;
// stack<string, list<string>> c1; // stack可以选择list或deque作为其底层结构
// stack<string, deque<string>> c2;
//stack<string, vector<string>> c3; // stack可以选择vector作为其底层结构
// 不能选择set或map作为其底层结构，没有push_back()、back()、pop_back()操作实现，编译错误
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "stack.size()= " << c.size() << endl;
    cout << "stack.top()= " << c.top() << endl;
    c.pop();
    cout << "stack.size()= " << c.size() << endl;
    cout << "stack.top()= " << c.top() << endl;
} // test_stack
} // namespace jj06




// 使用容器queue

#include <queue>

namespace jj07
{
void test_queue(long& value)
{
    cout << "test_queue()..........\n";

queue<string> c;
// queue<string, list<string>> c1; // queue可以选择list或deque作为其底层结构
// queue<string, deque<string>> c2;
//queue<string, vector<string>> c3; // queue不可以选择vector作为其底层结构，因为vector没有pop_front()实现，c3.pop();编译错误
// 不能选择set或map作为其底层结构，没有push_back()、back()、pop_back()操作实现，编译错误
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c.push(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "queue.size()= " << c.size() << endl;
    cout << "queue.front()= " << c.front() << endl;
    cout << "queue.back()= " << c.back() << endl;
    c.pop();
    cout << "queue.size()= " << c.size() << endl;
    cout << "queue.front()= " << c.front() << endl;
    cout << "queue.back()= " << c.back() << endl;
} // test_queue() 
} // namespace jj07




// 使用容器multiset

#include <set>

namespace jj08
{
void test_multiset(long& value)
{
    cout << "test_multiset()..........\n";

multiset<string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c.insert(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "multiset.size()= " << c.size() << endl;
    cout << "multiset.max_size()= " << c.max_size() << endl;

string target = get_a_target_string();
    {
    timeStart = clock();
auto pItem = ::find(c.begin(), c.end(), target); // 比c.find(...) 慢很多
    cout << "::find(), milli-seconds : " << (clock() - timeStart) << endl; //
    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
    }
    
    {
    timeStart = clock();
auto pItem = c.find(target);
    cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl; //
    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
    }
} // test_multiset() 
} // namespace jj08



// 使用容器unordered_multiset

#include <unordered_set>

namespace jj09
{
void test_unordered_multiset(long& value)
{
    cout << "test_unordered_multiset()..........\n";

unordered_multiset<string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c.insert(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "unordered_multiset.size()= " << c.size() << endl;
    cout << "unordered_multiset.max_size()= " << c.max_size() << endl;
    cout << "unordered_multiset.bucket_count()= " << c.bucket_count() << endl;
    cout << "unordered_multiset.load_factor()= " << c.load_factor() << endl;
    cout << "unordered_multiset.max_load_factor()= " << c.max_load_factor() << endl;
    cout << "unordered_multiset.max_bucket_count()= " << c.max_bucket_count() << endl;
    for(unsigned i=0; i< 20; ++i) {
        cout << "bucket #" << i << " has " << c.bucket_size(i) << " elements. \n";
    }

string target = get_a_target_string();
    {
    timeStart = clock();
auto pItem = ::find(c.begin(), c.end(), target); // 比c.find(...) 慢很多
    cout << "::find(), milli-seconds : " << (clock() - timeStart) << endl; //
    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
    }
    
    {
    timeStart = clock();
auto pItem = c.find(target);
    cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl; //
    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
    }
} // test_unordered_multiset() 
} // namespace jj09



// 使用容器unordered_multimap

#include <unordered_map>

namespace jj10
{
void test_unordered_multimap(long& value)
{
    cout << "test_unordered_multimap()..........\n";

unordered_map<long, string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            // multimap 不可使用[]进行insertion
            c.insert(pair<long, string>(i, string(buf)));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "unordered_multimap.size()= " << c.size() << endl;
    cout << "unordered_multimap.max_size()= " << c.max_size() << endl;

long target = get_a_target_long();
    timeStart = clock();
auto pItem = c.find(target);
    cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl; //
    if(pItem != c.end())
        cout << "found, " << (*pItem).second << endl;
    else
        cout << "not found!" << endl;
} // test_unordered_multimap() 
} // namespace jj10



// 使用容器set

#include <set>

namespace jj11
{
void test_set(long& value)
{
    cout << "test_set()..........\n";

set<string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c.insert(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "set.size()= " << c.size() << endl;
    cout << "set.max_size()= " << c.max_size() << endl;

string target = get_a_target_string();
    {
    timeStart = clock();
auto pItem = ::find(c.begin(), c.end(), target); // 比c.find(...) 慢很多
    cout << "::find(), milli-seconds : " << (clock() - timeStart) << endl; //
    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
    }
    
    {
    timeStart = clock();
auto pItem = c.find(target);
    cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl; //
    if(pItem != c.end())
        cout << "found, " << *pItem << endl;
    else
        cout << "not found!" << endl;
    }
} // test_set()   
} // namespace jj11



// 使用容器map

#include <map>

namespace jj12
{
void test_map(long& value)
{
    cout << "test_map()..........\n";

map<long, string> c;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c[i] = string(buf);
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    cout << "map.size()= " << c.size() << endl;
    cout << "map.max_size()= " << c.max_size() << endl;

long target = get_a_target_long();
    timeStart = clock();
auto pItem = c.find(target);
    cout << "c.find(), milli-seconds : " << (clock() - timeStart) << endl; //
    if(pItem != c.end())
        cout << "found, " << (*pItem).second << endl;
    else
        cout << "not found!" << endl;
} // test_map() 
} // namespace jj12




// 使用分配器allocator

#include <list>
#include <stdexcept>
#include <string>
#include <cstdlib>  // abort()
#include <cstdio>   // snprintf()
#include <algorithm>    // find()
#include <iostream>
#include <ctime>

#include <cstddef>
#include <memory>   // 内含 std::allocator

namespace jj13
{
void test_list_with_special_allocator(long& value)
{
    cout << "test_list_with_special_allocator().......... \n";

list<string, allocator<string>> c1;
char buf[10];

clock_t timeStart = clock();
    for(long i=0; i< value; ++i) {
        try {
            snprintf(buf, 10, "%d", rand());
            c1.push_back(string(buf));
        }
        catch(const exception& e) {
            cout << "i=" << i << " " << e.what() << endl;
            abort();
        }
    }
    cout << "milli-seconds : " << (clock() - timeStart) << endl; //
    
    // test allocator's allocate() & deallocate()
    int* p;
    allocator<int> alloc1;
    p = alloc1.allocate(1);
    cout << "alloc.max_size()= " << alloc1.max_size() << endl;
    alloc1.deallocate(p, 1);

    int *p1 = allocator<int>().allocate(512, (int*)0);
    allocator<int>().deallocate(p1, 512);

} // test_list_with_special_allocator()
} // namespace jj13



// 类模板 Class Templates

namespace jj14
{
// 复数类模板定义
template <typename T>
class complex
{
public:
    complex(T r = 0, T i = 0)
     : re(r), im(i)
    { }
    complex& operator += (const complex& _c)
    {
        (*this).re += _c.re;
        (*this).im += _c.im;
        return *this;
    }
    T real() const { return re; }
    T imag() const { return im; }
private:
    T re, im;

    friend complex<T>& __doapl(complex<T>* ths, const complex<T>& rhs);
};

template <typename T>
complex<T>& __doapl(complex<T>* ths, const complex<T>& rhs)
{
    ths->re += rhs.re;
    ths->im += rhs.im;
    return *ths;
}

void test_class_templates()
{
    cout << "test_class_templates().......... \n";

complex<double> c1(2.5, 1.5);
complex<int> c2(2, 6);
complex<int> c3(4, 12);
    c2 += c3;
    cout << "complex.real()=" << c2.real() << endl;
    cout << "complex.imag()=" << c2.imag() << endl;
}
}



// 函数模板 Function Templates

namespace jj15
{
class stone
{
public:
    stone() { }
    stone(int w, int h, int we)
     : _w(w), _h(h), _weight(we)
        { }
    bool operator<(const stone& rhs) const
        { return _weight < rhs._weight; }

    int w() const { return _w; }
    int h() const { return _h; }
    int weight() const { return _weight; }
    
private:
    int _w, _h, _weight;
};

template <class T>
inline
const T& min(const T& a, const T& b)
{
    return b < a ? b : a;
}

void test_function_templates()
{
    cout << "test_function_templates()........... \n";

stone r1(2,3, 13), r2(3,3, 10), r3;
    // 编译器对函数模板进行实参推导（argument deduction）
    // 实参推导的结果：T为stone，于是调用stone::operator<() 
    r3 = min(r1, r2);
    cout << "r3.w= " << r3.w() << ", h= " << r3.h() << ", weight= " << r3.weight() << endl;
}
} // namespace jj15


// 链表迭代器 list's iterator

namespace jj16
{
class Foo
{
public:
    void method(int i) { cout << "Foo::method(" << i << ")" << endl; }
public:
    int field;
};

void test_list_iterator()
{
    cout << "test_list_iterator().......... \n";

    {
    cout << "\npreincrement & postincrement ...... \n";

list<int> c;
    for(int i=0; i<10; ++i) c.push_back(i);

auto ite = c.begin();
    ++++ite;
    cout << "++++ite= " << *ite << endl; // 2
ite = c.begin();
    ++(++ite);
    cout << "++(++ite)= " << *ite << endl; // 2
ite = c.begin();
    ite.operator++().operator++();
    cout << "ite.operator++().operator++()= " << *ite << endl; // 2

ite = c.begin();
    ite++++;
    cout << "ite++++= " << *ite << endl; // 1
ite = c.begin();
    (ite++)++;
    cout << "(ite++)++= " << *ite << endl; // 1
ite = c.begin();
    ite.operator++(1).operator++(1);
    cout << "ite.operator++(1).operator++(1)= " << *ite << endl; // 1

int i(0);
    ++++i;
    cout << "++++i= " << i << endl; // 2
    //i++++; // 编译错误：表达式必须是可修改的左值
    //cout << "i++++= " << i << endl;
    }
    
    {
    cout << "\noperator* & operator-> ...... \n";
list<Foo>::iterator ite;
list<Foo> c;
    c.push_back(Foo());
    ite = c.begin();

    *ite; // 获得ite对象
    ite->method(1); // ->指针调用Foo::method
    (*ite).method(2); // 
    (&(*ite))->method(3);

    ite.operator->()->method(4); // operator->返回的是Foo*
    ite.operator*().method(5); // operator*返回的是Foo&
    
    ite->field = 10;
    (*ite).field = 11;
    (&(*ite))->field = 12;

    ite.operator->()->field = 10;
    ite.operator*().field = 11;
    cout << "field= " << ite->field << endl;
    } 
} // test_list_iterator
} // namespace jj16




// 测试各种容器的iterators的iterator_catagory

// input_iterator       output_iterator
//     ^
//     |
// forward_iterator
//     ^
//     |
// bidirectional_iterator
//     ^
//     |
// random_access_iterator

#include <iterator>

namespace jj17
{
// 特化
void _display_category(random_access_iterator_tag)
{ cout << "random_access_iterator" << endl; }
void _display_category(bidirectional_iterator_tag)
{ cout << "bidirectional_iterator" << endl; }
void _display_category(forward_iterator_tag)
{ cout << "forward_iterator" << endl; }
void _display_category(input_iterator_tag)
{ cout << "input_iterator" << endl; }
void _display_category(output_iterator_tag)
{ cout << "output_iterator" << endl; }

// 泛化
template <typename I>
void display_category(I iter)
{
    typename iterator_traits<I>::iterator_category cagy; // 向迭代器的萃取机提问
    _display_category(cagy);

    cout << "typeid(iter).name()= " << typeid(iter).name() << endl;
        // 输出依赖库的实现
}

void test_iterator_catagory()
{
    cout << "test_iterator_catagory()......... \n";

    display_category(array<int,10>::iterator()); // random_access_iterator
    display_category(vector<int>::iterator()); // random_access_iterator
    display_category(list<int>::iterator()); // bidirectional_iterator
    display_category(forward_list<int>::iterator()); // forward_iterator
    display_category(deque<int>::iterator()); // random_access_iterator

    display_category(set<int>::iterator()); // bidirectional_iterator
    display_category(map<int,int>::iterator()); // bidirectional_iterator
    display_category(multiset<int>::iterator()); // bidirectional_iterator
    display_category(multimap<int,int>::iterator()); // bidirectional_iterator
    display_category(unordered_set<int>::iterator()); // bidirectional_iterator
    display_category(unordered_map<int,int>::iterator()); // bidirectional_iterator
    display_category(unordered_multiset<int>::iterator()); // bidirectional_iterator
    display_category(unordered_multimap<int,int>::iterator()); // bidirectional_iterator
        // VS2015 MSVC14 中散列表的链表迭代器实现是双向链表迭代器

    display_category(istream_iterator<int>()); // input_iterator
    display_category(ostream_iterator<int>(cout, "")); // output_iterator
} 
} // namespace jj17



// 测试算法函数：accumulate

#include <iostream>     // std::cout
#include <algorithm>    // std::minus
#include <numeric>      // std::accumulate

namespace jj34
{
// 函数
int myfunc(int x, int y) { return x+2*y; }

// 对象
struct myclass {
    int operator()(int x, int y) { return x+2*y; }
} myobj;

void test_accumulate()
{
    int init = 100;
    int nums[] = {10, 20, 30};

    cout << "using default accumulate: ";
    cout << accumulate(nums, nums+3, init); // 160
    cout << "\n";

    cout << "using functional's minus: ";
    cout << accumulate(nums, nums+3, init, minus<int>()); // 40
    cout << "\n";

    cout << "using custom functions: ";
    cout << accumulate(nums, nums+3, init, myfunc); // 220
    cout << "\n";

    cout << "using custom objects: ";
    cout << accumulate(nums, nums+3, init, myobj); // 220
    cout << "\n";
} // test_accumulate()
} // namespace jj34




// 测试算法函数：for_each

#include <iostream>       // std::cout
#include <algorithm>      // std::for_each
#include <vector>         // std::vector

namespace jj35
{
void myfunc(int i) {
    cout << " " << i;
}

struct myclass {
    void operator()(int i) { cout << " " << i; }
} myobj;

void test_for_each()
{
    vector<int> myvec;
    myvec.push_back(10);
    myvec.push_back(20);
    myvec.push_back(30);

    for_each(myvec.begin(), myvec.end(), myfunc);
    cout << endl;   // output: 10 20 30

    for_each(myvec.begin(), myvec.end(), myobj);
    cout << endl;   // output: 10 20 30

    // sine c++11, range-based for statement
    for(auto& elem : myvec)
        elem += 5;
    
    for(auto elem : myvec)
        cout << " " << elem;    // output: 15 25 35
    cout << endl;
} // test_for_each()
} //namespace jj35



// 测试算法：replace, replace_if, replace_copy

#include <iostream>
#include <algorithm>
#include <list>

namespace jj36
{
void output_list(list<int>& list)
{
    for(auto elem : list)
        cout << " " << elem;
    cout << endl;
}

struct myclass {
    bool operator()(int value) { return value == 10; }
} myobj;

void test_replace_x()
{
    cout << "test_replace_x().......... \n";

    list<int> mylist {10, 20, 30};

    replace(mylist.begin(), mylist.end(), 20, 25);
        // 范围内所有等于20的值替换为25
    output_list(mylist);    // output: 10 25 30

    list<int> tlist;
    tlist.assign(mylist.begin(), mylist.end()); //
    replace_copy(mylist.begin(), mylist.end(), tlist.begin(), 30, 60); // 不管内存分配，直接赋值操作
        // 范围内所有等于30的值以60放入新区间，不符合的原值放入新区间
    output_list(mylist);    // output: 10 25 30
    output_list(tlist);    // output: 10 25 60

    replace_if(mylist.begin(), mylist.end(), myobj, 25);
        // 范围内所有满足myobj()条件的元素都替换成25
    output_list(mylist);    // output: 25 25 30
} // test_replace_x()
} // namespace jj36




// 测试函数：count, count_if, find, find_if

// 容器不带成员函数count(), find()
// array, vector, list, forward_list, deque

// 容器带有成员函数count(), find()。优先使用自己的成员函数
// set / multiset
// map / multimap
// unordered_set / unordered_multiset
// unordered_map / unordered_multimap

// namespace jj37
// {
    
// } // namespace jj37



void test_stl()
{
int select = 0;
    cout << "select: ";
    cin >> select;

    if(select == 1) {
        jj01::test_array();
        return;
    }
    else if(select == 14)
    {
        jj14::test_class_templates();
        return;
    }
    else if(select == 15)
    {
        jj15::test_function_templates();
        return;
    }
    else if(select == 16)
    {
        jj16::test_list_iterator();
        return;
    }
    else if(select == 17)
    {
        jj17::test_iterator_catagory();
        return;
    }
    else if(select == 34)
    {
        jj34::test_accumulate();
        return;
    }
    else if(select == 35)
    {
        jj35::test_for_each();
        return;
    }
    else if(select == 36)
    {
        jj36::test_replace_x();
        return;
    }

long value = 0;
    cout << "how many elements: ";
    cin >> value;

    switch (select)
    {
    case 2:
        jj02::test_vector(value); 
        break;
    case 3:
        jj03::test_list(value); 
        break;
    case 4:
        jj04::test_forward_list(value);
        break;
    case 5:
        jj05::test_deque(value);
        break;
    case 6:
        jj06::test_stack(value);
        break;
    case 7:
        jj07::test_queue(value);
        break;
    case 8:
        jj08::test_multiset(value);
        break;
    case 9:
        jj09::test_unordered_multiset(value);
        break;
    case 10:
        jj10::test_unordered_multimap(value);
        break;
    case 11:
        jj11::test_set(value);
        break;
    case 12:
        jj12::test_map(value);
        break;
    case 13:
        jj13::test_list_with_special_allocator(value);
        break;
    default:
        break;
    }
}


int main()
{
    test_stl();
#ifdef _MSC_VER
    system("pause");
#endif // _MSC_VER
    return 0;
}